package delegate;

import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

import recipe.RecipeData;

import manager.FileManager;
import model.DataManagerModel;

@SuppressWarnings("serial")
public abstract class CreateEditViewController extends JFrame{
	
	// Class data
	private static String DEFAULT_RECIPE_NAME  = "<Enter recipe name>";
	private static String DEFAULT_CATEGORY     = "<Enter category>";
	private static String DEFAULT_TAGS         = "<Enter tags>";
	private static String DEFAULT_INGREDIENTS  = "<Enter ingredients>";
	private static String DEFAULT_INSTRUCTIONS = "<Enter instructions>";
	
	private DataManagerModel dataModel      = null;
	private FileManager      dataManager    = null;
	private RecipeData       recipe         = null;
	
	private JLabel           lblRecipeName  = new JLabel("Recipe name");
	private JLabel           lblCategory    = new JLabel("Category");
	private JLabel           lblTags        = new JLabel("Tags");
	private JLabel           lblIngredients = new JLabel("Ingredients");
	private JLabel           lblInstructions = new JLabel("Instructions");
	private JLabel           lblImage       = new JLabel("Image");
	
	private JButton          btnDone        = new JButton("Done");
	private JButton          btnCancel      = new JButton("Cancel");
	private JButton          btnImageBrowse = new JButton("Browse");
	
	private JTextField       txtRecipeName  = new JTextField(DEFAULT_RECIPE_NAME, 30);
	private JTextField       txtCategory    = new JTextField(DEFAULT_CATEGORY, 15);
	private JTextField       txtTags        = new JTextField(DEFAULT_TAGS, 30);
	private JTextField       txtImage       = new JTextField(20);
	
	private JTextArea        txaIngredients = new JTextArea(DEFAULT_INGREDIENTS, 10, 30);
	private JTextArea        txaInstructions = new JTextArea(DEFAULT_INSTRUCTIONS, 10, 30);
	
	private File             imageFile      = null;
	private File             saveFile       = null;
	private BufferedImage    bi             = null;
	
	/**
	 * Constructor
	 * Description - Instantiates the view using the data model
	 * 
	 * @param model
	 */
	public CreateEditViewController(String title, DataManagerModel model, FileManager manager)
	{
		// Set model for viewController
		dataModel = model;
		dataManager = manager;
		if(manager != null){
			recipe = manager.getData();
		}
		
		// Set layout and properties
		JPanel view = new JPanel();
		view.setLayout(new GridBagLayout());
		this.setResizable(false);
		
		setComponentProperties();
		
		// Add components
		if(recipe != null){
			txtRecipeName.setText(recipe.getRecipeName());
			txtCategory.setText(recipe.getCategory());
			txaInstructions.setText(recipe.getInstructions());
			txaIngredients.setText(recipe.getListOfIngredients());
			txtTags.setText(recipe.getTags());
			txtImage.setText(recipe.getImageFileName());
		}
		
		view.add(lblRecipeName, setConstraints(0, 0, true));
		view.add(lblCategory, setConstraints(0, 1, false));
		view.add(lblTags, setConstraints(0, 2, false));
		view.add(lblIngredients, setConstraints(0, 3, false));
		view.add(lblInstructions, setConstraints(0, 4, false));
		view.add(lblImage, setConstraints(0, 5, false));
		
		
		view.add(txtRecipeName, setConstraints(1, 0, true));
		view.add(txtCategory, setConstraints(1, 1, false));
		view.add(txtTags, setConstraints(1, 2, false));
		view.add(txaIngredients, setIngredientsConstraints(1, 3));
		view.add(txaInstructions, setInstructionsConstraints(1, 4));
		view.add(txtImage, setConstraints(1, 5, false));
		view.add(btnImageBrowse, setConstraints(1, 6, false));

		view.add(btnDone, setConstraints(1, 7, false));
		view.add(btnCancel, setConstraints(1, 8, true));
		
		// Register listeners
		btnDone.addActionListener(new DoneClickedListener());
		btnCancel.addActionListener(new CancelClickedListener());
		btnImageBrowse.addActionListener(new BrowseClickedListener());
		txtRecipeName.addFocusListener(new TextFocusListener());
		txtCategory.addFocusListener(new TextFocusListener());
		txtTags.addFocusListener(new TextFocusListener());
		txaIngredients.addFocusListener(new TextFocusListener());
		txaInstructions.addFocusListener(new TextFocusListener());
		
		this.setContentPane(view);
		this.setTitle(title);
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		this.pack();
	} // Constructor
	
	private void setComponentProperties(){
		btnDone.setFocusable(true);
		btnCancel.setFocusable(true);
		txtRecipeName.setFocusable(true);
		txtCategory.setFocusable(true);
		txtTags.setFocusable(true);
		
		txtImage.setFocusable(true);
		txtImage.setEditable(false);
		
		txaIngredients.setWrapStyleWord(true);
		txaIngredients.setLineWrap(true);
		txaIngredients.setFocusable(true);
		
		txaInstructions.setWrapStyleWord(true);
		txaInstructions.setLineWrap(true);
		txaInstructions.setFocusable(true);
	}
	
	private GridBagConstraints setConstraints(int col, int row, boolean isTopOrBottom){
		GridBagConstraints gbc = new GridBagConstraints();
		Insets in;
		
		if(isTopOrBottom){
			in = new Insets(10, 10, 10, 10);
		}
		else{
			in = new Insets(10, 10, 0, 10);
		}
		
		gbc.gridx = col;
		gbc.gridy = row;
		gbc.insets = in;
		
		return gbc;
	}
	
	private GridBagConstraints setInstructionsConstraints(int col, int row){
		GridBagConstraints gbctxaInstructions = new GridBagConstraints();
		
		gbctxaInstructions.gridx = col;
		gbctxaInstructions.gridy = row;
		gbctxaInstructions.fill = GridBagConstraints.HORIZONTAL;
		gbctxaInstructions.insets = new Insets(10, 10, 10, 10);
		gbctxaInstructions.gridwidth = 3;
		
		return gbctxaInstructions;
	}
	
	private GridBagConstraints setIngredientsConstraints(int col, int row){
		GridBagConstraints gbcTxaIngredients = new GridBagConstraints();
		
		gbcTxaIngredients.gridx = col;
		gbcTxaIngredients.gridy = row;
		gbcTxaIngredients.fill = GridBagConstraints.HORIZONTAL;
		gbcTxaIngredients.insets = new Insets(10, 10, 0, 10);
		gbcTxaIngredients.gridwidth = 3;
		
		return gbcTxaIngredients;
	}
	
	private boolean saveImage(){
		boolean isSaved = false;
		try{
			if(bi != null && saveFile != null){
				ImageIO.write(bi, "jpg", saveFile);
				isSaved = true;
			}
		}
		catch(IOException io){
			io.printStackTrace();
		}
		
		return isSaved;
	}
	
	/**
	 * Method - validateInputFields
	 * Description - Checks all input fields for completion
	 * @return boolean
	 */
	private boolean validateInputFields(){
		boolean isInputOK = true;
		StringBuilder errorMessage = new StringBuilder("Please enter information for:\n");
		
		if(txtRecipeName.getText().equalsIgnoreCase(DEFAULT_RECIPE_NAME)){
			errorMessage.append("recipe name\n");
			isInputOK = false;
		}
		
		if(txtCategory.getText().equalsIgnoreCase(DEFAULT_CATEGORY)){
			errorMessage.append("category\n");
			isInputOK = false;
		}
		
		if(txtTags.getText().equalsIgnoreCase(DEFAULT_TAGS)){
			errorMessage.append("tags\n");
			isInputOK = false;
		}
		
		if(txaIngredients.getText().equalsIgnoreCase(DEFAULT_INGREDIENTS)){
			errorMessage.append("ingredients\n");
			isInputOK = false;
		}
		
		if(txaInstructions.getText().equalsIgnoreCase(DEFAULT_INSTRUCTIONS)){
			errorMessage.append("instructions\n");
			isInputOK = false;
		}
			
		if(!isInputOK){
			JOptionPane.showMessageDialog(this, errorMessage.toString(), 
					"Incomplete fields", JOptionPane.ERROR_MESSAGE);
		}
		
		return isInputOK;
	}
	
	/**
	 * Class - CancelClickedListener
	 * Description - Listener for the cancel button. Closes the view.
	 */
	private class CancelClickedListener implements ActionListener{
		
		public void actionPerformed(ActionEvent e){
			CreateEditViewController.this.dispose();
		}
	}
	
	/**
	 * Class - DoneClickedListener
	 * Description - Validates the field data and adds a filemanager
	 *               to the data model
	 */
	private class DoneClickedListener implements ActionListener
	{
		public void actionPerformed(ActionEvent e)
		{
			if(validateInputFields()){
				// Check for initialized manager (for edit view)
				if(dataManager != null){
					
					dataModel.setCurrentFileManager(dataManager);
					dataModel.modifyFileManager(txtRecipeName.getText(), txtCategory.getText(), 
							txaIngredients.getText(), txaInstructions.getText(), txtTags.getText(),
							txtImage.getText());
					
					saveImage();
					
					if(dataManager.closeFile()){
						JOptionPane.showMessageDialog(CreateEditViewController.this, "Edit success!");
						CreateEditViewController.this.dispose();
					}
					
				}
				// Check for initialized model (for create view)
				else if(dataModel != null){
					if(dataModel.addFileManager
					(txtRecipeName.getText(), txtCategory.getText(), 
					txaIngredients.getText(), txaInstructions.getText(), 
					txtTags.getText(), txtImage.getText())){
						
						saveImage();
									
						JOptionPane.showMessageDialog(CreateEditViewController.this, "Recipe created!");
						CreateEditViewController.this.dispose();
					}	
				}
			}
		}
	}
	
	private class BrowseClickedListener implements ActionListener{
		
		public void actionPerformed(ActionEvent e){
			
			JFileChooser browser = new JFileChooser("~");
			FileNameExtensionFilter filter = new FileNameExtensionFilter("JPEG file", "jpg", "jpeg");
			browser.setFileFilter(filter);
			
			int option = browser.showOpenDialog(CreateEditViewController.this);
			
			if(option == JFileChooser.APPROVE_OPTION){
				// Save file to database
				try{
					imageFile = browser.getSelectedFile();
					saveFile = new File("./rcp_db/Img_Files/" + imageFile.getName());
					bi = ImageIO.read(imageFile);
					
					CreateEditViewController.this.txtImage.setText(imageFile.getName());
				}
				catch(IOException io){
					io.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * Class - TextFocusListener
	 * Description - Listens for focus changes on components
	 * @author Ryne
	 *
	 */
	private class TextFocusListener implements FocusListener{
		
		/**
		 * Method - focusGained
		 * Description - Clears text in component if it is default
		 */
		public void focusGained(FocusEvent e){
			ComponentEvent ce = new ComponentEvent(e.getComponent(), e.getID());
			Component temp = ce.getComponent();
			if(temp instanceof JTextField){
				JTextField tf = (JTextField) temp;
				if(
					tf.getText().equalsIgnoreCase(DEFAULT_RECIPE_NAME) ||
					tf.getText().equalsIgnoreCase(DEFAULT_TAGS) ||
					tf.getText().equalsIgnoreCase(DEFAULT_CATEGORY)){
					tf.setText("");
				}
				
			}
			else if(temp instanceof JTextArea){
				JTextArea ta = (JTextArea) temp;
				if(
					ta.getText().equalsIgnoreCase(DEFAULT_INSTRUCTIONS) ||
					ta.getText().equalsIgnoreCase(DEFAULT_INGREDIENTS)
				){
					ta.setText("");
				}
			}
			// For debugging to see which component is selected
			//System.out.println("Component: " + temp);
		}
		
		/**
		 * Method - focusLost
		 * Description - Resets text in component if nothing was entered
		 */
		public void focusLost(FocusEvent e){
			ComponentEvent ce = new ComponentEvent(e.getComponent(), e.getID());
			Component temp = ce.getComponent();
			
			if(temp instanceof JTextField){
				JTextField tf = (JTextField) temp;
				if(tf.equals(txtRecipeName) && tf.getText().isEmpty()){
					tf.setText(DEFAULT_RECIPE_NAME);
				}
				else if(tf.equals(txtCategory) && tf.getText().isEmpty()){
					tf.setText(DEFAULT_CATEGORY);
				}
				else if(tf.equals(txtTags) && tf.getText().isEmpty()){
					tf.setText(DEFAULT_TAGS);
				}	
			}	
			else if(temp instanceof JTextArea){
				JTextArea ta = (JTextArea) temp;
				if(ta.equals(txaIngredients) && ta.getText().isEmpty()){
					ta.setText(DEFAULT_INGREDIENTS);
				}
				else if(ta.equals(txaInstructions) && ta.getText().isEmpty()){
					ta.setText(DEFAULT_INSTRUCTIONS);
				}
			}
		}
	}
	
} // CreateEditViewController
